/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package interpretadorportugolvisual.interpreter;

import br.org.isvi.interpretador.portugol.OperationResolver;
import br.org.isvi.interpretador.portugol.Resolver;
import br.org.isvi.interpretador.portugol.exception.SemanticErrorException;
import br.org.isvi.interpretador.portugol.types.BooleanSymbol;
import br.org.isvi.interpretador.portugol.types.IntegerSymbol;
import br.org.isvi.interpretador.portugol.types.Kind;
import br.org.isvi.interpretador.portugol.types.RealSymbol;
import br.org.isvi.interpretador.portugol.types.StringSymbol;
import br.org.isvi.interpretador.portugol.types.Symbol;
import br.org.isvi.interpretador.portugol.types.Variable;
import interpretadorportugolvisual.InputDialog;
import interpretadorportugolvisual.InterpretadorPortugolVisualApp;
import interpretadorportugolvisual.relatorios.Registrador;
import java.util.HashMap;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import javax.swing.JTextPane;

/**
 *
 * @author abraaoisvioliveirasouzadocarmo
 */
public class EditorResolver implements Resolver {

    private Logger log;
    private static final String ARQUIVO_LOG = "operacoes.txt";
    private boolean logarAtivo = false;
    JTextPane output;
    HashMap<String, Variable> variables = new HashMap<String, Variable>();
    Symbol[] stack = new Symbol[1024];
    int stackTop = -1;

    public EditorResolver(JTextPane output) {
        log = Logger.getLogger(ARQUIVO_LOG);
        this.output = output;

        try {
            FileHandler fh;
            fh = new FileHandler(ARQUIVO_LOG, true);
            log.addHandler(fh);
            log.setLevel(Level.ALL);
            SimpleFormatter formatter = new SimpleFormatter();
            fh.setFormatter(formatter);
        } catch (Exception e) {
        }
    }

    public void logar(String msg) {
        if (logarAtivo) {
            log.info(msg);
        }
    }

    public void error(String msg) {
        if (logarAtivo) {
            log.severe(msg);
        }
    }

    public void addToStack(Symbol obj) {
        try {
            stackTop++;
            stack[stackTop] = obj;

            logar("adicionou para o stack:" + obj.toString());
        } catch (Exception e) {
            throw new SemanticErrorException("Estouro de pilha");
        }
    }

    public Symbol popStack() {
        try {
            int last = stackTop;
            stackTop--;

            logar("removeu do stack:" + stack[last].toString());
            return stack[last];
        } catch (Exception e) {
            throw new SemanticErrorException("Estouro de pilha");
        }
    }

    public void declare(Variable obj) {
        if (variables.containsKey(obj.getName())) {
            throw new SemanticErrorException("Redeclaração de Variável: " + obj.getName());
        }

        variables.put(obj.getName(), obj);
    }

    public void endOPeration(OperationResolver opr) {
        Symbol ret = opr.execute();

        if (ret != null) {
            addToStack(ret);
        }
    }

    public void escreva(Symbol valor) {

        String text = output.getText();
        text = text + valor.toString();

        Registrador.registrarSaida(text);
        output.setText(text);
    }

    public void escrevaNL(Symbol valor) {
        escreva(valor);
        String text = output.getText();
        text = text + '\n';

        Registrador.registrarSaida(text);
        output.setText(text);
    }

    public Symbol getOPerationResult() {
        return popStack();
    }

    public void updateTarget(String target) {
        logar("Processando:" + target);
    }

    public Variable getVariable(String name) {
        if (!variables.containsKey(name)) {
            throw new SemanticErrorException("Variavel " + name + " não foi definida!");
        }

        return variables.get(name);
    }

    public void setLogarAtivo(boolean logarAtivo) {
        this.logarAtivo = logarAtivo;
    }

    public void performeHandlingError(String msg, int line, int col) {
        StringBuffer sbf = new StringBuffer();
        sbf.append("ERRO --> ").append(msg);

        if (line >= 0) {
            sbf.append(" na linha: ").append(line).append(" e coluna: ").append(col);
        }

        String text = output.getText();
        text = text + sbf.toString();
        text = text + '\n';

        Registrador.inserirErro(text);
        output.setText(text);

    }

    public int stackSize() {
        return stackTop;
    }

    public Symbol leia(Kind k) {
        Symbol ret = null;
        InputDialog input = new InputDialog(InterpretadorPortugolVisualApp.getApplication().getMainFrame(), true);
        input.setVisible(true);

        String value = null;

        try {
            value = input.getText();
        } catch (Exception e) {
            throw new SemanticErrorException("Não foi possivel ler a partir do buffer de entrada!");
        }

        switch (k) {
            case TEXTO:
                ret = new StringSymbol(value);
                break;
            case INTEIRO:
                ret = IntegerSymbol.valueOf(value);
                break;
            case BOOLEANO:
                ret = BooleanSymbol.valueOf(value);
                break;
            case REAL:
                ret = RealSymbol.valueOf(value);
                break;
            default:
                break;
        }

        return ret;
    }

    /**
     * Apenas para debug.
     */
    public void printStack() {

        for (int i = 0; i <= stackTop; i++) {
            System.out.println(stack[i]);
        }
    }

    public Variable setVariable(Variable var, Symbol sym) {
        Variable v = getVariable(var.getName());
        v.setValue(sym);

        return v;
    }
}
